﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Microsoft.TeamFoundation.Build.Client;

namespace BuildExplorer
{
    internal static class TreeViewTemplate
    {
        public static void RefreshBuildDetail(this TreeView tv, IBuildDetail build)
        {
            tv.Nodes.Clear();
            RebuildNodes(build.Information, tv.Nodes, containingAgentScope: null);
        }

        private static int RebuildNodes(IBuildInformation info, TreeNodeCollection currentNodes, IBuildInformationNode containingAgentScope)
        {
            int nodes = 0;
            int treeNodeIndex = 0;
            foreach (IBuildInformationNode node in info.Nodes)
            {
                if (node.Type == "ActivityProperties")
                {
                    continue; // ActivityProperties nodes are display in-line, in their parent node's listview
                }

                nodes++; // Don't count ActivityProperties, but do count BuildMessage

                if (node.Type == "BuildMessage")
                {
                    continue; // BuildMessage nodes are display in-line, in their parent node's listview

                }

                if (node.IsAgentScope())
                {
                    containingAgentScope = node;
                }

                var tn = new TreeNode();
                tn.ApplyTemplate(node, containingAgentScope);
                currentNodes.Insert(treeNodeIndex++, tn);

                int children = RebuildNodes(node.Children, tn.Nodes, containingAgentScope);

                nodes += children;
                // tn.Text += "  Nodes: " + (1 + children);  // self + children
            }

            return nodes;
        }

        public static IEnumerable<TreeNode> Flatten(this TreeNodeCollection nodes)
        {
            foreach (TreeNode item in nodes)
            {
                yield return item;
                foreach (TreeNode child in item.Nodes.Flatten())
                {
                    yield return child;
                }
            }
        }

        public static bool SelectNextMatch(this TreeView tv, Func<TreeNode, bool> predicate)
        {
            var flatten = tv.Nodes.Flatten();
            return SelectNextMatch(tv, flatten, predicate);
        }

        public static bool SelectPreviousMatch(this TreeView tv, Func<TreeNode, bool> predicate)
        {
            var flatten = tv.Nodes.Flatten().Reverse();
            return SelectNextMatch(tv, flatten, predicate);
        }

        private static bool SelectNextMatch(TreeView tv, IEnumerable<TreeNode> nodes, Func<TreeNode, bool> predicate)
        {
            var selected = nodes.SkipWhile(tn => !tn.IsSelected);
            if (!selected.Any())
            {
                selected = nodes;
            }
            else
            {
                selected = selected.Skip(1);
            }

            var match = selected.FirstOrDefault(predicate);
            if (match != null)
            {
                tv.SelectedNode = match;
                tv.Focus();
                return true;
            }

            return false;
        }

        public static void ExpandAllMatches(this TreeView tv, Func<TreeNode, bool> predicate)
        {
            tv.BeginUpdate();
            var flatten = tv.Nodes.Flatten();
            foreach (TreeNode node in flatten.Where(predicate))
            {
                tv.SelectedNode = node;
            }
            tv.Focus();
            tv.EndUpdate();
        }
    }
}
